package com.sharer.last.utils;

import com.sharer.last.base.utils.StringUtil;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.List;

public class ExceptionUtil {


    /**
     * *获取错误信息
     *
     * @return
     */
    public static String getErrorMessage(Exception ex) {
        StringBuilder sb = new StringBuilder();
        if (StringUtil.isNotEmpty(ex.getMessage())) {
            sb.append(ex.getMessage());
        } else {
            sb.append(getFullErrorMessage(ex));
        }
        return sb.toString();
    }

    /**
     * *获取错误详情
     *
     * @return
     */
    public static String getFullErrorMessage(Exception ex) {
        StringBuilder sb = new StringBuilder();
        StackTraceElement[] elements = ex.getStackTrace();
        String exceptionName = ExceptionUtil.getExceptionName(ex);
        String exceptionMessage = ExceptionUtil.getExceptionMessage(ex);
        Integer lineNumber = 0;
        if (CheckUtil.isNotEmpty(elements)) {
            StackTraceElement element = elements[0];
            lineNumber = element.getLineNumber();
        }
        sb.append("exceptionlineNumber:" + lineNumber);
        sb.append(",exceptionName:" + exceptionName);
        sb.append(",exceptionMessage:");
        sb.append(exceptionMessage);
        return sb.toString();
    }

    /**
     * 将ErrorStack转化为String.
     *
     * @param ex Throwable
     * @return {String}
     */

    public static String getExceptionMessage(Throwable ex) {
//        FastStringWriter stringWriter = new FastStringWriter();
//        ex.printStackTrace(new PrintWriter(stringWriter));
//        stringWriter.close();
//        return stringWriter.toString();
        String msg = null;
        if (ex instanceof UndeclaredThrowableException) {
            Throwable targetEx = ((UndeclaredThrowableException) ex).getUndeclaredThrowable();
            if (targetEx != null) {
                msg = targetEx.getMessage();
            }
        } else {
            msg = ex.getMessage();
        }
        return msg;
    }

    public static String getExceptionName(Throwable ex) {
        return ex.getClass().getName();
    }


    /**
     * @param bindingResult bindingResult
     * @return bindingResult错误内容
     */
    public static String resolveBindingResult(BindingResult bindingResult) {
        if (bindingResult == null || CollectionUtils.isEmpty(bindingResult.getFieldErrors())) {
            return "";
        }
        StringBuilder    errorMsg       = new StringBuilder();
        List<FieldError> fieldErrorList = bindingResult.getFieldErrors();
        for (FieldError fieldError : fieldErrorList) {
            errorMsg.append("[")
                    .append(fieldError.getField())
                    .append(":")
                    .append(fieldError.getDefaultMessage())
                    .append("]");
        }
        return errorMsg.toString();
    }


    /**
     * 将CheckedException转换为UncheckedException.
     *
     * @param e Throwable
     * @return {RuntimeException}
     */
    public static RuntimeException unchecked(Throwable e) {
        if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
                || e instanceof NoSuchMethodException) {
            return new IllegalArgumentException(e);
        } else if (e instanceof InvocationTargetException) {
            return new RuntimeException(((InvocationTargetException) e).getTargetException());
        } else if (e instanceof RuntimeException) {
            return (RuntimeException) e;
        } else {
            return new RuntimeException(e);
        }
    }

    /**
     * 代理异常解包
     *
     * @param wrapped 包装过得异常
     * @return 解包后的异常
     */
    public static Throwable unwrap(Throwable wrapped) {
        Throwable unwrapped = wrapped;
        while (true) {
            if (unwrapped instanceof InvocationTargetException) {
                unwrapped = ((InvocationTargetException) unwrapped).getTargetException();
            } else if (unwrapped instanceof UndeclaredThrowableException) {
                unwrapped = ((UndeclaredThrowableException) unwrapped).getUndeclaredThrowable();
            } else {
                return unwrapped;
            }
        }
    }
}
